package cn.com.xiaoyaoji.plugins.http;


import com.alibaba.fastjson.JSON;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.*;

public class Https {
	
	// 初始化
	private static CloseableHttpClient client;
	
	private static DefaultHttpClient httpsClient;
	
	static{
		//client = HttpClients.custom().setDefaultCookieStore(new BasicCookieStore()).build();
		
		//创建httpclient连接池  
		PoolingHttpClientConnectionManager httpClientConnectionManager = new PoolingHttpClientConnectionManager();  
        //设置连接池最大数量  
        httpClientConnectionManager.setMaxTotal(200);  
        //设置单个路由最大连接数量  
        httpClientConnectionManager.setDefaultMaxPerRoute(20);
		
		// 设置连接获取超时时间
        // 设置请求超时时间
        RequestConfig requestConfig = RequestConfig.custom()  
                .setConnectTimeout(10000)  
                .setSocketTimeout(30000)  
                .setCookieSpec(CookieSpecs.BEST_MATCH).build();
        // 声明重定向策略对象  
        client = HttpClients.custom().setConnectionManager(
        		httpClientConnectionManager).setDefaultRequestConfig(requestConfig).build();  
        
//        try{
//        	SSLSocketFactory sf = new SSLSocketFactoryEx(null);
//    		sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
//
//    		HttpParams params = new BasicHttpParams();
//    		HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
//    		HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
//
//    		// 设置http https支持
//    		SchemeRegistry registry = new SchemeRegistry();
//    		registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
//    		registry.register(new Scheme("https", sf, 443));
//
//    		ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
//    		httpsClient = new DefaultHttpClient(ccm);
//        }catch(Exception ex){
//
//        }
	}
	
	private static <T> ResponseMessage<T> toResponseMessage(
			HttpResponse response) {
		return toResponseMessage(response, null);
	}
	
	private static <T> ResponseMessage<T> toResponseMessage(HttpResponse response, Class<T> clazz){
		ResponseMessage<T> resp = new ResponseMessage<T>();
		resp.setResultCode(response.getStatusLine().getStatusCode());
		resp.setEntity(response.getEntity());
		try {
			resp.setResponseBody(EntityUtils.toString(response.getEntity()));
			if(null != clazz){
				T result = JSON.parseObject(resp.getResponseBody(), clazz);
				resp.setResult(result);
			}
		} catch (Exception e) {
		}
		return resp;
	}
	
	public static ResponseMessage<?> get(String url) throws Exception {
		HttpGet httpget = new HttpGet(url);
		HttpResponse response = client.execute(httpget);
		return toResponseMessage(response);
	}
	
	@SuppressWarnings("rawtypes")
	public static ResponseMessage get(String url, Map<String, Object> paramMap) 
			throws Exception {
		HttpGet httpget = new HttpGet(url + "?" + mapToGetParam(paramMap));
		HttpResponse response = client.execute(httpget);
		return toResponseMessage(response);
	}
	
	public static <T> ResponseMessage<T> get(String url, Map<String, Object> paramMap,Class<T> clazz) 
			throws Exception {
		HttpGet httpget = new HttpGet(url + "?" + mapToGetParam(paramMap));
		HttpResponse response = client.execute(httpget);
		return toResponseMessage(response,clazz);
	}
	
	/*
	 * 数据发送可以采用其它的方式
	 */
	@SuppressWarnings("rawtypes")
	public static ResponseMessage postWithType(String url, String bodyString) throws ClientProtocolException, IOException {
		HttpPost post = new HttpPost(url);        
		// 创建StringEntity对象
		StringEntity formEntiry = new StringEntity(bodyString, Charset.forName("UTF-8"));
		post.setEntity(formEntiry);
		post.addHeader("Content-type", "application/octet-stream");
		//不用代理
		HttpResponse response = client.execute(post);
		return toResponseMessage(response);
	}
	
	/*
	 * 数据发送可以采用其它的方式
	 */
	@SuppressWarnings("rawtypes")
	public static ResponseMessage postWithType(String url, String bodyString, String charset) throws ClientProtocolException, IOException {
		HttpPost post = new HttpPost(url);        
		// 创建StringEntity对象
		StringEntity formEntiry = new StringEntity(bodyString, Charset.forName(charset));
		post.setEntity(formEntiry);
		post.addHeader("Content-type", "application/octet-stream");
		//不用代理
		HttpResponse response = client.execute(post);
		return toResponseMessage(response);
	}
	
	/*
	 * 数据发送可以采用其它的方式
	 */
	@SuppressWarnings("rawtypes")
	public static ResponseMessage post(String url, String bodyString) throws ClientProtocolException, IOException {
		HttpPost post = new HttpPost(url);        
		// 创建StringEntity对象
		StringEntity formEntiry = new StringEntity(bodyString, Charset.forName("UTF-8"));
		post.setEntity(formEntiry);
//		post.addHeader("Content-type", "application/x-www-form-urlencoded");
//		post.setHeader("Content-Type", "text/html;charset=UTF-8");
		//不用代理
		HttpResponse response = client.execute(post);
		return toResponseMessage(response);
	}
	
	/*
	 * 数据发送可以采用其它的方式
	 */
	@SuppressWarnings("rawtypes")
	public static ResponseMessage httpsPost(String url, Map<String, Object> paramMap) 
			throws IllegalStateException, IOException {
		HttpPost post = new HttpPost(url);        
		// 创建UrlEncodedFormEntity对象
		UrlEncodedFormEntity formEntiry = 
				new UrlEncodedFormEntity(mapToPostParam(paramMap), "UTF-8");
		post.setEntity(formEntiry);
		//不用代理
		HttpResponse response = httpsClient.execute(post);
		return toResponseMessage(response);
	}
	
	/*
	 * 数据发送可以采用其它的方式
	 */
	@SuppressWarnings("rawtypes")
	public static ResponseMessage post(String url, Map<String, Object> paramMap) 
			throws IllegalStateException, IOException {
		HttpPost post = new HttpPost(url);        
		// 创建UrlEncodedFormEntity对象
		UrlEncodedFormEntity formEntiry = 
				new UrlEncodedFormEntity(mapToPostParam(paramMap), "UTF-8");
		post.setEntity(formEntiry);
		//不用代理
		HttpResponse response = client.execute(post);
		return toResponseMessage(response);
	}
	
//	public static HttpResponse xml(String url, Map<String, Object> paramMap) throws IllegalStateException, IOException {
//		// 目标地址
//		HttpPost httppost = new HttpPost(url);
//		// 构造最简单的字符串数据 TODO:xml逻辑暂时注释
//		StringEntity reqEntity = null;
//		// 设置类型
//		reqEntity.setContentType("application/xml");
//		// 设置请求的数据
//		httppost.setEntity(reqEntity);
//		// 执行
//		HttpResponse httpresponse = client.execute(httppost);
//		/*HttpEntity entity = httpresponse.getEntity();
//		String body = EntityUtils.toString(entity);
//		System.out.println(body);*/
//		return httpresponse;
//	}
	
	private static List<NameValuePair> mapToPostParam(Map<String, Object> paramMap) {
		return mapToPostParam(paramMap,true);
	}
	
	@SuppressWarnings("rawtypes")
	private static List<NameValuePair> mapToPostParam(Map<String, Object> paramMap, boolean withSign) {
		List<NameValuePair> parameters = new ArrayList<NameValuePair>();
		Iterator<String> it = paramMap.keySet().iterator();
		while (it.hasNext()) {
			String key = String.valueOf(it.next());
			Object value = paramMap.get(key);
			if(value instanceof Collection){
				Collection collection = (Collection) value;
				for(Object obj : collection){
					parameters.add(new BasicNameValuePair(key, String.valueOf(obj)));
				}
			}else{
				parameters.add(new BasicNameValuePair(key, String.valueOf(value)));
			}
			
		}
		// 是否需要生成签名
		if(withSign){
			if(!paramMap.containsKey("secretKey")){
				throw new RuntimeException("生成签名缺少必要参数:secretKey");
			}
			String secretKey = String.valueOf(paramMap.get("secretKey"));
			parameters.add(new BasicNameValuePair("apiSign", calculateSign(paramMap, secretKey)));
		}
		return parameters;
	}
	
	/**
	 * 对参数进行签名
	 * @param paramMap
	 * @param secretKey
	 * @return
	 */
	@SuppressWarnings("deprecation")
	public static String calculateSign(Map<String, Object> paramMap, String secretKey) {
		// 参数取参数名再按照字母升序重新排
		String[] keyArray = paramMap.keySet().toArray(new String[0]);
		Arrays.sort(keyArray);
		// 拼接有序的参数名-值串
		StringBuilder stringBuilder = new StringBuilder("");
		for (String key : keyArray) {
			stringBuilder.append(key).append(paramMap.get(key));
		}
		stringBuilder.append(secretKey);
		String codes = stringBuilder.toString();
		String sign = DigestUtils.shaHex(codes).toUpperCase();
		return sign; 
	}
	
	// 默认要生成签名
	private static String mapToGetParam(Map<String, Object> params) {
		return mapToGetParam(params,false);
	}

	@SuppressWarnings("rawtypes")
	private static String mapToGetParam(Map<String, Object> params, boolean withSign) {
		StringBuilder param = new StringBuilder();
		Iterator it = params.keySet().iterator();
		while (it.hasNext()) {
			String key = String.valueOf(it.next());
			Object value = params.get(key);
			if(value instanceof Collection){
				Collection collection = (Collection)value;
				for(Object obj : collection){
					param.append(key).append("=").append(String.valueOf(obj)).append("&");
				}
			}else{
				param.append(key).append("=").append(value).append("&");
			}
		}
		// 是否需要生成签名
		if(withSign){
			if(!params.containsKey("secretKey")){
				throw new RuntimeException("生成签名缺少必要参数:secretKey");
			}
			String secretKey = String.valueOf(params.get("secretKey"));
			params.put("sign", calculateSign(params, secretKey));
		}
		
		String s = param.toString();
		if (s.endsWith("&")) {
			s = s.substring(0, s.length() - 1);
		}
		return s;
	}
	
	public static void main(String[] args) throws Exception{
		String url = "http://61.178.73.154:9001/ws/MainServlet?wsdl";
		ResponseMessage<?> resp =  Https.get(url);
		System.out.println("响应状态码:" + resp.getResultCode());
		System.out.println(resp.getResponseBody());
	}
	
}
